# -*- coding:utf-8 -*-
from controller.kvm_hypervisor import KVM
from controller.vmware_hypervisor import VMware
import os
from controller.hypervisor import Hypervisor
import pymysql


class HypervisorManager(object):

    kvm = KVM()
    vmware = VMware()

    def __init__(self):
        # 创建数据库libvirt
        db_conn_temp = pymysql.connect(host='localhost', port=3306, user='root', passwd='1234qwer')
        cursor = db_conn_temp.cursor()
        if not cursor:
            print('连接数据库失败')
            raise Exception('连接数据库失败')
        libvirt_exit_or_not_sql = "SELECT * FROM information_schema.SCHEMATA where SCHEMA_NAME='libvirt'"
        if cursor.execute(libvirt_exit_or_not_sql) == 0:
            cursor.execute("create database if not exists libvirt")
        cursor.execute("USE libvirt")
        try:
            # 创建表 vmware_defined (记录用户手动定义的vmware名称及路径，路径不包括文件名)
            cursor.execute("create table vmware_defined(name varchar(20), path varchar(1000), runningState int(8))")
            cursor.close()
        except:
            # print ('libvirt数据库及其中的vmware_defined表格已经存在')
            # raise Exception('数据库或vmware_defined表创建失败')
            pass

        db_conn = pymysql.connect(host='localhost',
                                  port=3306,
                                  user='root',
                                  passwd='1234qwer',
                                  db='libvirt')
        cursor = db_conn.cursor()
        if not cursor:
            print('连接数据库失败')
            raise Exception('连接数据库失败')
        try:
            # 创建表 defined_name_and_path_lists ，该路经包含文件（镜像）名称，作用为如下三点：
            # 删除 kvm 镜像时寻找路径使用
            # 向 vmware 的 vmx 文件中写入端口及删除镜像时寻找路径使用
            # 判断当前镜像是否已经被使用
            cursor.execute("create table defined_name_and_path_lists(name varchar(20), path varchar(1000)) ")
            cursor.close()
        except:
            # print ('libvirt数据库及其中的 defined_name_and_path_lists 表格已经存在')
            # raise Exception('数据库或defined_name_and_path_lists表创建失败')
            pass

        HypervisorManager.kvm.init_define(False)
        HypervisorManager.vmware.init_define(True)

    @classmethod
    def new(cls, image_path, vm_name, cpu, memory):
        check_image_path_valid = False
        rootdir = os.path.abspath(os.path.join(image_path, os.pardir))
        for lists in os.listdir(rootdir):
            path = os.path.join(rootdir, lists)
            if path == image_path:
                check_image_path_valid = True
                break
        CPU_output = os.popen('cat /proc/cpuinfo | grep "processor" | wc -l')
        max_CPU_num = int(CPU_output.read())
        mem_output = os.popen('cat /proc/meminfo | grep "MemTotal"')
        max_mem_num = int(mem_output.read().split()[1])

        if not check_image_path_valid:
            print ("hypervisor_manager: 输入虚拟机镜像路径不存在，新建虚拟机失败")
            raise Exception('输入虚拟机镜像路径不存在')
        elif cls.kvm.check_imagepath_used_or_not(image_path) or cls.vmware.check_imagepath_used_or_not(image_path):
            print ('hypervisor_manager: 该虚拟机镜像已经被使用，新建虚拟机失败')
            raise Exception('该虚拟机镜像已经被使用，新建虚拟机失败')
        elif len(vm_name) < 0 or len(vm_name) > 20:
            print ("hypervisor_manager: 输入虚拟机名称数不合法（请输入1 ~ 20），新建虚拟机失败")
            raise Exception('输入虚拟机名称数不合法')
        elif cls.kvm.check_vmname_used_or_not(vm_name) or cls.vmware.check_vmname_used_or_not(vm_name):
            print ('hypervisor_manager: 该虚拟机名称已经被使用，新建虚拟机失败')
            raise Exception('该虚拟机名称已经被使用，新建虚拟机失败')
        elif not cpu.isdigit():
            print ("hypervisor_manager: 输入cpu数不合法（请输入数字），新建虚拟机失败")
            raise Exception('输入cpu数不合法')
        elif int(cpu) > max_CPU_num or int(cpu) <= 0:
            print ("hypervisor_manager: 输入cpu数不合法（请输入1 ~ %d），新建虚拟机失败" %max_CPU_num)
            raise Exception('输入cpu数不合法')
        elif not memory.isdigit():
            print ("hypervisor_manager: 输入内存数不合法（请输入数字），新建虚拟机失败")
            raise Exception('输入内存数不合法')
        elif int(memory) > max_mem_num or int(memory) < 524288:
            print ("hypervisor_manager: 输入内存数不合法（请输入524288 ~ %d），新建虚拟机失败" %max_mem_num)
            raise Exception('输入内存数不合法')
        else:
            template_xml_path = os.path.abspath(os.path.join(os.path.dirname(__file__)))
            path = os.path.abspath(os.path.join(image_path, os.pardir))
            if os.path.splitext(image_path)[1] == '.qcow2' or os.path.splitext(image_path) =='.raw':
                os.popen("cp " + template_xml_path + "/kvm.xml " + path).read()
                cls.kvm.define(path + "/kvm.xml", image_path, vm_name, cpu, memory)
            elif os.path.splitext(image_path)[1] == '.vmdk':
                os.popen("cp " + template_xml_path + "/vmware.xml " + path).read()
                cls.vmware.define(path + "/vmware.xml", image_path, vm_name, cpu, memory)

    @classmethod
    def delete(cls, usrname, delete_image_or_not):
        if cls.kvm.check_defined_instance(usrname):
            cls.kvm.undefine(usrname, delete_image_or_not)
            cls.delete_image(usrname, delete_image_or_not, 'true')
        elif cls.vmware.check_defined_instance(usrname):
            cls.vmware.undefine(usrname, delete_image_or_not)
            cls.delete_image(usrname, delete_image_or_not, 'false')


    @classmethod
    def delete_image(cls, usrname, delete_image_or_not, is_kvm):
        if delete_image_or_not.lower() == 'true':
            if is_kvm == 'true':
                cls.kvm.delete_image(usrname, delete_image_or_not)
            elif is_kvm == 'false':
                cls.vmware.delete_image(usrname, delete_image_or_not)
            else:    # 不会走到此分支
                pass
        elif delete_image_or_not.lower() == 'false':
            pass
        else:
            print ("hypervisor_manager: 传参不合法（第二个参数请输入true/false）")
            raise Exception('输入参数不合法')

    @classmethod
    def start(cls, usrname):
        if cls.kvm.check_defined_instance(usrname):
            cls.kvm.start(usrname, False)
        elif cls.vmware.check_defined_instance(usrname):
            # done: write vmx file to add " RemoteDisplay.vnc.enabled = "TRUE" RemoteDisplay.vnc.port = "5900""
            kvm_port_list = cls.kvm.get_all_kvm_started_ports_list()
            vmware_port_list = cls.vmware.get_all_vmware_started_ports_list()
            lists = []
            for kvm_port in kvm_port_list:
                lists.append(kvm_port)
            for vmware_port in vmware_port_list:
                lists.append(vmware_port)
            lists.sort()
            if len(lists) > 0:
                new_port = int(lists[len(lists) - 1]) + 1
            else:
                new_port = 5900

            path = cls.get_defined_path(usrname)
            print('hypervisor_manager: %s' % path)
            file_obj = open(path + "/" + usrname + ".vmx", 'a')
            file_obj.write('RemoteDisplay.vnc.enabled = "TRUE"' + '\n')
            file_obj.write('RemoteDisplay.vnc.port = ' + '"' + str(new_port) + '"')
            file_obj.close()
            cls.vmware.start(usrname, True)
            # done: vmware_defined 数据库更改runningState状态为：1 （运行状态）

    @classmethod
    def shutdown(cls, usrname):
        if cls.kvm.check_started_list(usrname):
            cls.kvm.shutdown(usrname, False)
        elif cls.vmware.check_started_list(usrname):
            cls.vmware.shutdown(usrname, True)
            # done: vmware_defined 数据库更改runningState状态为：-1 （关机状态）

    @classmethod
    def pause(cls, usrname):
        if not cls.kvm.check_started_list(usrname) and not cls.vmware.check_started_list(usrname):
            pass
        else:
            aa = cls.get_detail_info(usrname).running_state
            if aa == 3:
                print ('hypervisor_manager: 当前已经处于paused暂停状态，不能进行pause操作')
                raise Exception('当前处于paused暂停状态，不能进行pause操作')
            if cls.kvm.check_started_list(usrname):
                cls.kvm.pause(usrname, False)
            elif cls.vmware.check_started_list(usrname):
                cls.vmware.pause(usrname, True)
                # done: vmware_defined 数据库更改runningState状态为：3 （暂停状态）

    @classmethod
    def resume(cls, usrname):
        if not cls.kvm.check_started_list(usrname) and not cls.vmware.check_started_list(usrname):
            pass
        else:
            if cls.get_detail_info(usrname).running_state == 1:
                print ('hypervisor_manager: 当前处于started运行状态，不能进行resume操作')
                raise Exception('当前处于started运行状态，不能进行resume操作')
            if cls.kvm.check_started_list(usrname):
                cls.kvm.resume(usrname, False)
            elif cls.vmware.check_started_list(usrname):
                cls.vmware.resume(usrname, True)
                # done: vmware_defined 数据库更改runningState状态为：1 （运行状态）

    @classmethod
    def get_defined_name_and_path_lists(cls):
        return Hypervisor.get_defined_name_and_path_lists()

    @classmethod
    def get_defined_path(cls, vm_name):
        return Hypervisor.get_defined_path(vm_name)

    @classmethod
    def check_defined_list(cls, usrname):
        return cls.kvm.check_defined_instance(usrname) or cls.vmware.check_defined_instance(usrname)

    @classmethod
    def check_started_list(cls, usrname):
        return cls.kvm.check_started_list(usrname) or cls.vmware.check_started_list(usrname)

    @classmethod
    def get_vnc_port(cls, usrname):
        if cls.kvm.check_started_list(usrname):
            return cls.kvm.get_kvm_vnc_port(usrname)
        elif cls.vmware.check_started_list(usrname):
            return cls.vmware.get_vmware_vnc_port(usrname)

    @classmethod
    def list(cls):
        results = []
        kvm_defined = cls.kvm.list_defined()
        vmware_defined = cls.vmware.list_defined()
        kvm_started = cls.kvm.list_started()
        vmware_started = cls.vmware.list_started()
        for name in kvm_defined:
            info = vmInfo(name, 'kvm', '关机', 'NA')
            results.append(info)
        for name in vmware_defined:
            info = vmInfo(name, 'vmware', '关机', 'NA')
            results.append(info)
        for name in kvm_started:
            status = 'NA'
            if cls.get_detail_info(name).running_state == 1:
                status = '运行'
            elif cls.get_detail_info(name).running_state == 3:
                status = '暂停'
            info = vmInfo(name, 'kvm', status, cls.get_vnc_port(name))
            results.append(info)
        for name in vmware_started:
            status = 'NA'
            # 查数据库 取运行状态字段
            if int(cls.get_detail_info(name).running_state) == 1:
                status = '运行'
            elif int(cls.get_detail_info(name).running_state) == 3:
                status = '暂停'
            info = vmInfo(name, 'vmware', status, cls.get_vnc_port(name))
            results.append(info)
        print ('')
        print ('name' + ', ' + 'type' + ', ' + 'status' + ', ' + 'port')
        for item in results:
            print (item.vm_name + ', ' + item.vm_type + ', ' + item.vm_status + ', ' + item.port)

        return results

    @classmethod
    def list_detail_info(cls):
        lists = []
        kvm_lists = cls.kvm.list_detail_info()
        vmware_lists = cls.vmware.list_detail_info()
        for item in kvm_lists:
            lists.append(item)
        for item in vmware_lists:
            lists.append(item)
        for item in lists:
            """
            print ('ID = %d' % item.id)
            print ('Name = %s' % item.name)
            print ('Running State = %d' % item.running_state)
            print ('Max Memory = %d' % item.max_memory)
            print ('Memory = %d' % item.memory)
            print ('Number of virt CPUs = %d' % item.number_CPU)
            print ('CPU Time (in s) = %d' % item.CPU_time)
            print (' ')
            """
        return lists

    @classmethod
    def get_detail_info(cls, usrname):
        item = None
        if cls.kvm.check_started_list(usrname):
            item = cls.kvm.get_detail_info(usrname, False)
        elif cls.vmware.check_started_list(usrname):
            item = cls.vmware.get_detail_info(usrname, True)
            # done: vmware_defined 从数据库中获取runningState状态

        return item


    @classmethod
    def get_shutdown_detail_info(cls, vm_name):
        if cls.kvm.check_defined_instance(vm_name):
            return cls.kvm.get_shutdown_vm_detail_info(vm_name)
        elif cls.vmware.check_defined_instance(vm_name):
            return cls.vmware.get_shutdown_vm_detail_info(vm_name)


    @classmethod
    def close_conn(cls):
        cls.kvm.close_conn()
        cls.vmware.close_conn()


class vmInfo(object):
    def __init__(self, vm_name, vm_type, vm_status, port):
        self.vm_name = vm_name
        self.vm_type = vm_type
        self.vm_status = vm_status
        self.port = port

